use leptos::leptos_dom::ev::SubmitEvent;
use leptos::*;
use serde::{Deserialize, Serialize};
use wasm_bindgen::prelude::*;
use tracing::{debug, error, info};
use leptos::logging;
use serde_json::*;


#[derive(Default, Debug, serde::Serialize, serde::Deserialize, Clone )]
struct CustomResponse {
  filename: String,
  other_val: usize,
}

#[wasm_bindgen]
extern "C" {
    // invoke without arguments
    #[wasm_bindgen(js_namespace = ["window", "__TAURI__", "core"], js_name = invoke)]
    async fn invoke_without_args(cmd: &str) -> JsValue;

    // invoke with arguments (default)
    #[wasm_bindgen(js_namespace = ["window", "__TAURI__", "core"])]
    async fn invoke(cmd: &str, args: JsValue) -> JsValue;
}

#[derive(Serialize, Deserialize)]
struct GreetArgs<'a> {
    name: &'a str,
}

#[derive(Serialize, Deserialize)]
struct AsyncArgs {
    name:String
}

#[component]
pub fn App() -> impl IntoView {    
  
  let (router, set_router) = create_signal(0i32);

  view! {        
    <nav align="center">
      <a href="#" on:click=move |_| { set_router.set(0);}>"Home"<img src="public/tauri.svg" height="30px" /> </a>       
      <button on:click=move |_| { set_router.set(1); }   >"TablePage"</button>     
      <button on:click=move |_| { set_router.set(2);}   >"SelectPage"</button>  
      <a href="#" on:click=move |_| { set_router.set(3);}>"InputForm"</a> " | "     
      <a href="#" on:click=move |_| { set_router.set(4);}>"MoreForm"</a>       
    </nav>  
    <main class="container">                                              
      <div>
      {
        move || {
     
            let rid = router.get();
            if rid == 1 {
              view! { <TablePage />  }
              }else if rid == 2 {
                view! { <SelectPage />    }             
              }else if rid == 3 {
                view! { <InputFormPage /> }
              }else if rid == 4 {
                view! { <FuncPage /> }
              }else { 
                view! { <HomePage /> }
              }
        }
     }

      </div>      
      </main>              
    }
}


#[component]
pub fn TablePage() -> impl IntoView {

  let sv:Vec<CustomResponse> = vec![];
  let (hello_msg, set_hello_msg) = create_signal(sv); 

  let hello = move |ev: SubmitEvent| {
    ev.prevent_default();
    spawn_local(async move {         
        let name = "test";
        let args = serde_wasm_bindgen::to_value(&GreetArgs { name: &name }).unwrap();
        // Learn more about Tauri commands at https://v2.tauri.app/develop/calling-rust/#commands
        let new_msg = invoke("hello", args).await.as_string().unwrap();           
        let sv:Vec<CustomResponse> = serde_json::from_str(&new_msg).unwrap();
        set_hello_msg.set( sv );
    });
  };

  view!{
      <form class="row" on:submit=hello>           
              <button type="submit">"click to read files"</button>   
      </form> <br/>                    
      <div class="row">          
          <table border="1" cellpadding="0" cellspacing="0" id="futures"><tr><td>Id</td><td>Name</td></tr>                       
          { move || {                
              let recs = hello_msg.get();
                  recs.into_iter().enumerate().map(|(id, s)| view! { <tr align="left"> <td>{id+1}</td> <td>{s.filename}</td></tr> }).collect_view()            
              } 
          }
          </table >       
      </div>
  }
    
}

#[component]
pub fn SelectPage() -> impl IntoView {
    
    let (png_name, set_png_name) = create_signal(String::from("AP501"));   
    view! {         
            <div>        
            <MyPngSelect on:change=move |ev| { 
              let v = event_target_value(&ev);      
              set_png_name.set(format!("{}", v))  }/>
           <br/>    
            {
                move || {
                    let file_name = format!("public/{}.png", png_name.get());
                    view! {
                        <img src=file_name width="100%" />
                    }
                }
             }              
             </div>   
             <div>
             <MySelect />
             </div>        
    }
}

#[component]
fn MySelect()-> impl IntoView {
    let (value, set_value) = create_signal(0i32);
view! {
  <select style="width: 100px; font-size: 18px;"
    on:change=move |ev| {
      let new_value = event_target_value(&ev);
      let new_value = new_value.parse::<i32>().unwrap();
      set_value.set(new_value);
    }
    prop:value=move || value.get().to_string()
  >
    <option value="0">"0"</option>
    <option value="1">"1"</option>
    <option value="2">"2"</option>
  </select>
  // 一个循环选择选项的按钮
  <button on:click=move |_| set_value.update(|n| {
    if *n == 2 {
      *n = 0;
    } else {
      *n += 1;
    }
  })>
    "Next Option"
  </button>

  <p>"Selected: " {move || value.get().to_string()} </p>

}

}


#[component]
fn MyPngSelect()-> impl IntoView {    
  view! {
    <select style="width: 100px; font-size: 18px;">
      <option value="AP501">"AP501"</option>
      <option value="rb2501">"rb2501"</option>
      <option value="hc2501">"hc2501"</option>
      <option value="MA501">"MA501"</option>
      <option value="SR501">"SR501"</option>
      <option value="SA501">"SA501"</option>
    </select>
  }
}

#[component]
fn HomePage()-> impl IntoView {
    
view! {
  "getting started..."<br/>
  <div align="left">
  <li> <a href="https://v2.tauri.app/develop/" target="_blank">tauri V2.0</a>  </li>
  <li> <a href="https://leptos.shantou.university/cn/getting_started/index.html" target="_blank">leptos </a>  </li>
  </div>
  <h2>"hello, tauri&leptos!"</h2>
  <div align="left">
  <li> "TablePage ：异步调用后台命令（tauri async command，返回json数据), 并进行表格（style）展示。"</li>
  <li> "SelectPage ：使用select标签，选择内容，并进行异步响应显示。"</li>
  <li> "InputForm ：Form中使用input，输入内容，并进行异步响应显示。"</li>
  <li> "InputForm ：Webview,AppHandle,State在async command中的使用！"</li>
  <li> "MoreForm ：checkbox, radio功能展示"</li>
  </div>

}

}

#[component]
fn InputFormPage()-> impl IntoView {
  // input box中的value  
  let (name, set_name) = create_signal(String::new());
  // 显示区域的展示文本
  let (greet_msg, set_greet_msg) = create_signal(String::new());

  let update_name = move |ev| {
    let v = event_target_value(&ev);
    set_name.set(v);
  };

  let greet = move |ev: SubmitEvent| {
      ev.prevent_default();
    // 如果需要调用异步函数，则需要使用spawn_local， 参加TablePage的hello函数
      let name = name.get_untracked();
      if name.is_empty() {
          return;
      }          
      let new_msg = format!("hello, {}", name);
      set_greet_msg.set(new_msg);  
  };
 

  view! {
      <form class="row" on:submit=greet>
      <input
          id="greet-input"
          placeholder="Enter a name..."
          on:input=update_name
      />
      <button type="submit">"Greet"</button>   
    </form>     
    <p><b>{ move || greet_msg.get() }</b></p>

    <div align="left">
    "Commands can access the WebviewWindow instance that invoked the message:"<br/>
    "#[tauri::command]"<br/>
    "async fn my_custom_command(webview_window: tauri::WebviewWindow) {"<br/>
    "   let lab =  webview_window.label().clone();"<br/>
    "//特别注意，WebviewWindow的必须在异步command中调用"<br/>
    "// 异步command的参数和返回值不同于同步command"<br/>   
   <br/>
    <button on:click=move |_| { 
        spawn_local(async move {                      
          // Learn more about Tauri commands at https://v2.tauri.app/develop/calling-rust/#commands
          let str = invoke_without_args("my_webview_command" ).await.as_string().unwrap_or_default();
          set_greet_msg.set( format!("webview info:{}", str) );         
      });

    }  >"webview info"</button>  
  </div>

  <div align="left">
  "Commands can access an AppHandle instance:"<br/>
  "#[tauri::command]"<br/>
  "async fn my_custom_command(app_handle: tauri::AppHandle) {"<br/>
  "  let app_dir = app_handle.path_resolver().app_dir();"<br/>
  "// 特别注意，AppHandle的必须在异步command中调用"<br/>
  "// 异步command的参数和返回值不同于同步command" <br/>
    <br/>
    <button on:click=move |_| {

      spawn_local(async move {                  
        // Learn more about Tauri commands at https://v2.tauri.app/develop/calling-rust/#commands
        let str = invoke_without_args("my_app_command").await.as_string().unwrap_or_default(); 
        set_greet_msg.set( format!("app info:{}", str) );                  
      });

     }  >"App handle"</button>  
  </div>

  <div align="left">
  "Commands with State:"<br/>
  "#[tauri::command]"<br/>
  "fn greet(state: tauri::State<'_, SharedState>, name: &str) -> Result<String,String> {"<br/>
  "  Ok(format!('Hello {}, tauri::State! Your state.startup is {}!', name, state.startup))"<br/>
  "}"<br/>
  "// 同步command参数不支持State，异步command可以！!" <br/>
    <br/>
    <button on:click=move |_| {

      spawn_local(async move {                  
        // Learn more about Tauri commands at https://v2.tauri.app/develop/calling-rust/#commands
        let args = serde_wasm_bindgen::to_value(&GreetArgs { name: "State" }).unwrap();
        // Learn more about Tauri commands at https://v2.tauri.app/develop/calling-rust/#commands        
        let str = invoke("greet", args ).await.as_string().unwrap_or_default(); 
        set_greet_msg.set( format!("command with State info:{}", str) );                  
      });

     }  >"State in command(Failure)"</button>  

     <button on:click=move |_| {
      spawn_local(async move {                  
        // Learn more about Tauri commands at https://v2.tauri.app/develop/calling-rust/#commands
        let args = serde_wasm_bindgen::to_value(&GreetArgs { name: "State" }).unwrap();
        // Learn more about Tauri commands at https://v2.tauri.app/develop/calling-rust/#commands        
        let str = invoke("async_greet", args ).await.as_string().unwrap_or_default(); 
        set_greet_msg.set(str);                  
      });

     }  >"State in async-command(OK)"</button>  
  </div>

  }

}


#[component]
fn FuncPage()-> impl IntoView {

  let (input_val, set_input_val) = create_signal("".to_string());
  let (checked_val, set_checked_val) = create_signal(1);
  let (select_val, set_select_val) = create_signal(1);
        
  let update_select = move |ev| {
    let v = event_target_value(&ev);    
    set_input_val.set(v.clone());
    let iv = v.parse::<i32>().unwrap_or(1);
    set_select_val.set(iv);
  };

  let update_check = move |ev| {
    //ev.prevent_default();
    // event_prevent_default(&ev);
    let is_checked = event_target_checked(&ev);
    let v = event_target_value(&ev);
    let iv = v.parse::<i32>().unwrap_or(1);    
    let mark = if iv==1 { 1 } else if iv==2 { 2 } else { 4 };
     // set_input_val.set(v);
     if is_checked {
       set_input_val.set( format!("{} checked", v) );
       let mut vv = checked_val.get();
       vv |= mark;
       set_checked_val.set(vv);
     }else {          
      set_input_val.set( format!("{} unchecked", v) );       
      let mut vv = checked_val.get();
      vv &= !mark;
      set_checked_val.set(vv);
     }
  };

view! {
  <div align="center">  
  <table border="1" cellpadding="0" cellspacing="0" id="futures" width="100%" >
  <tr><td width="30%"> lastest action </td><td align="left">
  {
    move || {
        let src = format!("{}",input_val.get());
        view! {        
           {src}          
        }
    }
 }
  </td></tr>
  <tr><td>checkbox val </td><td align="left">
 {
    move || {
        let src = format!("{}",checked_val.get());
        view! {        
           {src}          
        }
    }
 }
 </td></tr>
 <tr><td>radio val</td><td align="left"> 
 {
  move || {
      let src = format!("{}", select_val.get());
      view! {      
         {src}        
      }
  }
}            
</td></tr>
<tr><td>checkbox</td><td align="left">
  <form>
    <input type="checkbox" checked id="vehicle1" name="vehicle1" value="1" on:change = update_check />
    <label for="vehicle1"> 我有自行车 </label><br/>
    <input type="checkbox" id="vehicle2" name="vehicle2" value="2" on:change = update_check />
    <label for="vehicle2"> 我有汽车 </label><br/>
    <input type="checkbox" id="vehicle3" name="vehicle3" value="3" on:change = update_check />
    <label for="vehicle3"> 我有船 </label><br/>
  </form>
</td></tr>
<tr><td>radio</td><td align="left">
<form>
  <input type="radio" id="html" checked name="fav_language" value="1"  on:change = update_select  />
  <label for="html">HTML</label><br/>
  <input type="radio" id="css" name="fav_language" value="2" on:change = update_select />
  <label for="css">CSS</label><br/>
  <input type="radio" id="javascript" name="fav_language" value="3" on:change = update_select />
  <label for="javascript">JavaScript</label>
</form>
</td></tr>
</table>  
</div>
}

}
